<html>
    <head>
        <title>验证  Validation</title>
    </head>
    <body>
        <script>
            // 验证 Validation

                    /*
                        验证系统用于验证用户输入或客户端对特定控制器动作或服务方法的请求。

                        ABP与ASP.NET核心模型验证系统兼容，其留档中写入的所有内容对于基于ABP的应用程序都已经有效。
                        因此，本文档主要关注ABP功能，而不是重复Microsoft文档。


                        此外，ABP还增加了以下好处：

                            ★、定义 "IValidationEnabled" 以将自动验证添加到任意类。
                                  由于所有应用程序服务都固有地实现了它，因此它们也会自动验证。

                            ★、自动本地化数据注释属性的验证错误。

                            ★、提供可扩展服务来验证方法调用或对象状态

                            ★、提供FluentValiri集成。
                    */

                    /*
                        一、验证Dto

                               本节简要介绍验证系统。有关详细信息，请参阅ASP.NET core 验证文档。 


                               1、数据注解特性(Data Annotation Attributes)) 

                                    使用数据注释是一种以声明方式实现DTO的形式验证的简单方法:
                                        public class CreateBookDto
                                        {
                                            [Required]
                                            [StringLength(100)]
                                            public string Name { get; set; }

                                            [Required]
                                            [StringLength(1000)]
                                            public string Description { get; set; }

                                            [Range(0, 999.99)]
                                            public decimal Price { get; set; }
                                        }
                                    当你将此类用作应用程序服务或控制器的参数时，它会自动验证并抛出本地化验证异常（并由ABP处理）  
                                    
                                    
                               2、IValidateableObject接口
                                    IValidatableObject可以由DTO实现以执行自定义验证逻辑。  
                                    CreateBookDto实现此接口并检查Name是否等于Description并在这种情况下返回验证错误：
                                        
                                                using System.Collections.Generic;
                                                using System.ComponentModel.DataAnnotations;

                                                namespace Acme.BookStore
                                                {
                                                    public class CreateBookDto : IValidatableObject // 实现IValidatableObject接口
                                                    {
                                                        [Required]
                                                        [StringLength(100)]
                                                        public string Name { get; set; }

                                                        [Required]
                                                        [StringLength(1000)]
                                                        public string Description { get; set; }

                                                        [Range(0, 999.99)]
                                                        public decimal Price { get; set; }


                                                        // 自定义验证逻辑
                                                        public IEnumerable<ValidationResult> Validate(
                                                            ValidationContext validationContext)
                                                        {
                                                            if (Name == Description)
                                                            {
                                                                yield return new ValidationResult(
                                                                    "Name and Description can not be the same!",
                                                                    new[] { "Name", "Description" }
                                                                );
                                                            }
                                                        }
                                                    }
                                                }

                                    ★、往自定义验证逻辑中解析服务依赖
                                                如果你需要从依赖注入系统解析服务，你可以使用ValidationContext对象。
                                            
                                            eg:  var myService = validationContext.GetRequiredService<IMyService>();

                                        虽然在Validate方法中解析服务允许任何可能性，但在DTO中实现域验证逻辑并不是一个好的做法。
                                        保持DTO简单。它们的目的是传输数据（DTO：数据传输对象）。
                    */

                    /*
                        二、验证相关的基础设施

                                1、IValidationEnable接口
                                        IValidationEnabled是一个空标记接口，可以由任何类实现（注册到DI并从其解析），以让ABP为类的方法执行验证系统。
                                        eg：
                                            using System.Threading.Tasks;
                                            using Volo.Abp.DependencyInjection;
                                            using Volo.Abp.Validation;

                                            namespace Acme.BookStore
                                            {
                                                public class MyService : ITransientDependency, IValidationEnabled
                                                {
                                                    public virtual async Task DoItAsync(MyInput input)
                                                    {
                                                        //...
                                                    }
                                                }
                                            }

                                        ABP使用动态代理/拦截系统来执行验证。为了使其工作，你的方法应该是虚拟或者你的服务应该通过接口注入和使用（如IMyService）

                                2、启用/禁用验证
                                        可以使用[DisableValidation]对方法、类和属性禁用它

                                        eg：

                                            [DisableValidation]
                                            public Void MyMethod()
                                            {
                                            }

                                            [DisableValidation]
                                            public class InputClass
                                            {
                                                public string MyProperty { get; set; }
                                            }

                                            public class InputClass
                                            {
                                                [DisableValidation]
                                                public string MyProperty { get; set; }
                                            }
                                      
                                3、AbpValidationException　验证异常类：

                                            一旦ABP确定了一个验证错误，它会抛出一个类型为AbpValidationException的异常。
                                            你的应用程序代码可以抛出AbpValidationException，但大多数时候不需要。

                                            AbpValidationException的属性包含验证错误列表。

                                            AbpValidationException的日志级别设置为Warning。它将所有验证错误记录到日志系统。

                                            AbpValidationException被ABP自动捕获并转换为可用错误并带有HTTP 400状态代码。有关详细信息，请参阅异常处理文档。
                    */

                    /*
                        三、高级选项 
                                除了自动验证之外，你可能还需要手动验证对象。在这种情况下，注入并使用IObjectValidator服务：

                                        1、ValidateAsync方法根据验证规则验证给定对象，如果它不处于有效状态，则抛出AbpValidationException。

                                        2、GetErrorsAsync不会引发异常，但只返回验证错误；

                            ★、IObjectValidator 
                                    IObjectValidator默认由ObjectValidator实现。ObjectValidator是可扩展的；
                                    你可以实现IObjectValidationContributor接口来贡献自定义逻辑。
                                    示例：
                                        public class MyObjectValidationContributor
                                            : IObjectValidationContributor, ITransientDependency
                                        {
                                            public Task AddErrorsAsync(ObjectValidationContext context)
                                            {
                                                // 获取当前要验证的对象
                                                var obj = context.ValidatingObject;

                                                //Add the validation errors if available
                                                context.Errors.Add(...);
                                                return Task.CompletedTask;
                                            }
                                        }
                                    请记住将你的类注册到DI（实现ITransientDependency就像在这个例子中一样）、

                                    ABP将自动发现你的类并用于任何类型的对象验证（包括自动方法调用验证）。

                            ★、IMethodInvocationValidator 方法调用验证
                                    IMethodInvocationValidator用于验证方法调用。
                                    它在内部使用IObjectValidator来验证传递给方法调用的对象。
                                    你通常不需要此服务，因为它由框架自动使用，但在极少数情况下，你可能希望在应用程序中重用或替换它。

                            ★、Fluent验证集成
                                    Volo. Abp.FluentValiri软件包将Fluent验证库集成到验证系统中（通过实现IObjectValidationContributor）。
                                    有关更多信息，请参阅FluentValidationIntegration文档。
                    */
        </script>
    </body>
</html>